﻿using Engine;
using Engine.Graphics;
using Engine.Media;
using Game;
using GameEntitySystem;
using SAGhoul.Blocks;
using SAGhoul.ParticleSystem;
using SAGhoul.Tartareosity;
using System.Collections.Generic;

namespace SAGhoul
{
	public class SAGModLoader : ModLoader
	{
		readonly Game.Random m_random = new();
		public override void __ModInitialize()
		{
			ModsManager.RegisterHook("OnProjectLoaded", this);
			ModsManager.RegisterHook("ChangeSkyColor", this);
			ModsManager.RegisterHook("ProcessAttackment", this);
			ModsManager.RegisterHook("CalculateCreatureInjuryAmount", this);
			ModsManager.RegisterHook("DeadBeforeDrops", this);
			ModsManager.RegisterHook("OnModelRendererDrawExtra", this);
			ModsManager.RegisterHook("DecideLoot", this);
			ModsManager.RegisterHook("OnPlayerSpawned", this);
			ModsManager.RegisterHook("SetClothes", this);
			ModsManager.RegisterHook("InitializeCreatureTypes", this);
			SAGhoulsManager.Initialize();

		}
		public SubsystemSAG SubsystemSAG
		{
			get; set;
		}
		public SubsystemTartareosity SubsystemTartareosity
		{
			get; set;
		}
		public override void OnProjectLoaded(Project project)
		{
			SubsystemSAG = project.FindSubsystem<SubsystemSAG>();
			SubsystemTartareosity = project.FindSubsystem<SubsystemTartareosity>();
			SAGhoulsManager.SubsystemSAG = SubsystemSAG;
		}
		public override Color ChangeSkyColor(Color oldColor, Vector3 direction, float timeOfDay, int temperature)
		{
			if (SubsystemSAG != null)
			{
				int max = MathUtils.Min(200, MathUtils.Max(oldColor.R, oldColor.G, oldColor.B));
				Color result = oldColor;
				if (SubsystemTartareosity?.WorldType == WorldType.Tartareosity)
				{
					if (SubsystemSAG.SkyBrightness > 0)
					{
						float num = SubsystemSAG.SkyBrightness;
						result = new Color((int)MathUtils.Round(255f * num), (int)MathUtils.Round(255f * num), (int)MathUtils.Round(255f * num));
					}
					else if (SubsystemSAG.SkyColorFactor > 0)
						result = new Color(max + (int)MathUtils.Round(22f * SubsystemSAG.SkyColorFactor), max, max + (int)MathUtils.Round(55f * SubsystemSAG.SkyColorFactor));
					else
						result = new Color(45, 50, 115);
				}
				else
				{
					if (SubsystemSAG.SkyColorFactor > 0)
					{
						result = new Color(max + (int)MathUtils.Round(22f * SubsystemSAG.SkyColorFactor), max, max + (int)MathUtils.Round(55f * SubsystemSAG.SkyColorFactor));
					}
					else if (SAGhoulsManager.IsDuringBloodMoon(SubsystemSAG))
					{
						result = new Color(max + 55, max, max);
					}
					if (SubsystemSAG.SkyBrightness > 0)
					{
						float num = SubsystemSAG.SkyBrightness;
						result = new Color((int)MathUtils.Round(255f * num), (int)MathUtils.Round(255f * num), (int)MathUtils.Round(255f * num));
					}
				}
				return result;
			}
			return oldColor;
		}

		public override void ProcessAttackment(Attackment attackment)
		{
			Entity target = attackment.Target, attacker = attackment.Attacker;
			ComponentSAGhouls componentSAGhouls_target = target.FindComponent<ComponentSAGhouls>();
			if (componentSAGhouls_target != null)
			{
				if (componentSAGhouls_target.IsTough)
				{
					attackment.ImpulseFactor = 0;
					attackment.StunTimeAdd = 0;
				}
			}
			else if (attacker != null)
			{
				ComponentSAGhouls componentSAGhouls_attacker = attacker.FindComponent<ComponentSAGhouls>();
				if (componentSAGhouls_attacker != null)
				{
					if (componentSAGhouls_attacker.KnockBackAttacking)
					{
						attackment.ImpulseFactor *= 5f;
						attackment.StunTimeSet = 3f;
					}
				}
			}
			if (attackment is ProjectileAttackment projectileAttackment)
			{
				ComponentBulletDefender componentBulletDefender = target.FindComponent<ComponentBulletDefender>();
				if (componentBulletDefender != null)
				{
					bool hitHead = componentBulletDefender.HitHead(projectileAttackment.HitPoint);
					if (hitHead)
					{
						projectileAttackment.AttackPower *= componentBulletDefender.HeadHitDamageMultiplier;
						FloatingImageParticleSystem particleSystem = new(
							componentBulletDefender.ComponentCreature.ComponentCreatureModel.EyePosition + 0.5f * Vector3.UnitY,
							0.8f * Vector3.UnitY + attacker?.FindComponent<ComponentBody>()?.Velocity ?? Vector3.Zero,
							new Vector2(0.25f), Color.White, 1.2f, "Textures/HitHead");
						target.Project.FindSubsystem<SubsystemParticles>(throwOnError: true).AddParticleSystem(particleSystem);
					}
					else
						projectileAttackment.AttackPower *= componentBulletDefender.NonHeadHitDamageMultiplier;
				}
			}

		}


		public override void CalculateCreatureInjuryAmount(Injury injury)
		{
			ComponentHealth componentHealth = injury.ComponentHealth;
			bool isAttackerGhoul = false, isAttackerPlayer = false, isTargetGhoul = false, isTargetPlayer = false;
			var attacker = injury.Attacker;
			if (attacker != null)
			{
				if (attacker.Entity.FindComponent<ComponentSAGhouls>() != null)
					isAttackerGhoul = true;
				if (attacker.Entity.FindComponent<ComponentPlayer>() != null)
					isAttackerPlayer = true;
			}
			ComponentSAGhouls componentSAGhouls_target = componentHealth.Entity.FindComponent<ComponentSAGhouls>();
			if (componentSAGhouls_target != null)
			{
				isTargetGhoul = true;
				if (isAttackerGhoul)
				{//清空尸鬼间的友伤
					injury.Amount = 0;
					return;
				}
				bool injuryLimit = false;
				if (componentSAGhouls_target.IsBoss && !injury.Cause.Contains(SAGhoulsManager.GetBlockDisplayName(typeof(SAGArtifactBlock))))
				{//所有boss的50%减伤
					injury.Amount *= 0.5f;
					if (componentSAGhouls_target.EntityName.Contains("Dark"))
					{
						injuryLimit = true;
					}
				}
				if (componentSAGhouls_target.EntityName.Contains("SAGhoul_Bear"))
					injuryLimit = true;
				if (injuryLimit)
				{//时间段免伤
					if (componentSAGhouls_target.m_injuryLimit >= ComponentSAGhouls.MaxInjury)
						injury.Amount = 0.01f / componentHealth.AttackResilience;
					else
					{
						float injuryAmount = injury.Amount * componentHealth.AttackResilience;
						if (injuryAmount >= ComponentSAGhouls.MaxInjury)
						{
							injury.Amount = ComponentSAGhouls.MaxInjury / componentHealth.AttackResilience;
							injuryAmount = ComponentSAGhouls.MaxInjury;
						}
						componentSAGhouls_target.m_injuryLimit += injuryAmount;
					}
				}
			}
			ComponentClothingMass componentClothingMass = componentHealth.Entity.FindComponent<ComponentClothingMass>();
			if (componentClothingMass != null)
			{
				isTargetPlayer = true;
				if (isAttackerGhoul && injury.Attackment != null)
				{
					float damageReductionFactor = componentClothingMass.ArmorProtection * 0.7f;//全套护甲防御最大不超过70%
					float attackResilience = componentHealth.AttackResilience * componentHealth.AttackResilienceFactor;
					float finalDamage = injury.Attackment.AttackPower / attackResilience * (1f - damageReductionFactor);
					injury.Amount = finalDamage;
				}
			}
			Difficulty difficulty = componentHealth.Project?.FindSubsystem<SubsystemSAG>()?.Difficulty ?? Difficulty.Normal;
			if (isTargetPlayer && isAttackerGhoul)
			{//尸鬼对玩家的伤害
				float multipler = 1f;
				switch (difficulty)
				{
					case Difficulty.VeryEasy: multipler = 0.25f; break;
					case Difficulty.Easy: multipler = 0.66f; break;
					case Difficulty.Hard: multipler = 1.5f; break;
					case Difficulty.VeryHard: multipler = 3f; break;
				}
				injury.Amount *= multipler;
			}
			if (isTargetGhoul && isAttackerPlayer)
			{//玩家对尸鬼的伤害
				float multipler = 1f;
				switch (difficulty)
				{
					case Difficulty.VeryEasy: multipler = 3f; break;
					case Difficulty.Easy: multipler = 1.5f; break;
					case Difficulty.Hard: multipler = 0.66f; break;
					case Difficulty.VeryHard: multipler = 0.25f; break;
				}
				injury.Amount *= multipler;
			}
		}
		public override void DeadBeforeDrops(ComponentHealth componentHealth, ref KillParticleSystem killParticleSystem, ref bool dropAllItems)
		{
			ComponentSAGhouls componentSAGhouls = componentHealth.Entity.FindComponent<ComponentSAGhouls>();
			if (componentSAGhouls != null && !componentSAGhouls.DropItemInHand)
				dropAllItems = false;
		}
		public override void OnModelRendererDrawExtra(SubsystemModelsRenderer modelsRenderer, SubsystemModelsRenderer.ModelData modelData, Camera camera, float? alphaThreshold)
		{
			ComponentModel componentModel = modelData.ComponentModel;
			ComponentAquagaze componentAquagaze = componentModel.Entity.FindComponent<ComponentAquagaze>();
			if (componentAquagaze != null)
			{
				ComponentBody componentBody = componentAquagaze.ComponentCreature.ComponentBody;
				Vector3 position = Vector3.Transform(componentBody.Position + 1.02f * Vector3.UnitY * componentBody.BoxSize.Y, camera.ViewMatrix);
				if (position.Z < 0f)
				{
					Color baseColor = Color.Lerp(Color.Red, Color.Green, componentAquagaze.FeedRate);
					Color color = Color.Lerp(baseColor, Color.Transparent, MathUtils.Saturate((position.Length() - 4f) / 3f));
					if (color.A > 8)
					{
						string text = $"Lv{MathUtils.Floor(componentAquagaze.GrowthLevel):0}  {componentAquagaze.GrowthRate * 100f:0.0}%";
						Vector3 right = Vector3.TransformNormal(0.005f * Vector3.Normalize(Vector3.Cross(camera.ViewDirection, Vector3.UnitY)), camera.ViewMatrix);
						Vector3 down = Vector3.TransformNormal(-0.005f * Vector3.UnitY, camera.ViewMatrix);
						BitmapFont font = LabelWidget.BitmapFont;
						modelsRenderer.PrimitivesRenderer.FontBatch(font, 1, DepthStencilState.None, RasterizerState.CullNoneScissor, BlendState.AlphaBlend, SamplerState.LinearClamp)
							.QueueText(text, position, right, down, color, TextAnchor.HorizontalCenter | TextAnchor.Bottom);
					}
				}
			}
		}
		public override void DecideLoot(ComponentLoot componentLoot, List<BlockDropValue> dropValues)
		{
			base.DecideLoot(componentLoot, dropValues);
			ComponentAquagaze componentAquagaze = componentLoot.Entity.FindComponent<ComponentAquagaze>();
			if (componentAquagaze != null)
			{
				dropValues.Clear();
				if (componentAquagaze.SoulCondensed)
				{
					if (componentAquagaze.GrowthLevel >= ComponentAquagaze.MaxLevel && m_random.Bool(1f))//满级有几率掉落大块灵魂残渣
						dropValues.Add(new BlockDropValue(typeof(LargeSoulsResidueBlock).BlockIndex(), 1));
				}
				else
				{//未投喂灵魂凝固，正常分配掉落物
					dropValues.Add(new BlockDropValue(RawFishBlock.Index,//鱼肉战利品
						MathUtils.Max(1, (int)(MathUtils.Floor(ComponentAquagaze.SumFeeds(componentAquagaze.GrowthLevel) * ComponentAquagaze.FeedConversionRatio)))));
					if (componentAquagaze.GrowthLevel >= ComponentAquagaze.MaxLevel)//满级额外掉落灵魂残渣
						dropValues.Add(new BlockDropValue(typeof(SoulsResidueBlock).BlockIndex(),
							m_random.Int(1, 3)));
				}
			}
		}
		public override bool OnPlayerSpawned(PlayerData.SpawnMode spawnMode, ComponentPlayer componentPlayer, Vector3 position)
		{
			if (componentPlayer != null && spawnMode == PlayerData.SpawnMode.Respawn)
			{//玩家重生获得灵魂养料
				SubsystemSAG subsystem = componentPlayer.Project.FindSubsystem<SubsystemSAG>(throwOnError: true);
				if (subsystem.NourishmentAcquiredCount < 5)
				{
					int value = typeof(SoulNourishmentBlock).BlockIndex();
					if (ComponentInventoryBase.FindAcquireSlotForItem(componentPlayer.ComponentMiner.Inventory, value) >= 0)
						ComponentInventoryBase.AcquireItems(componentPlayer.ComponentMiner.Inventory, value, 1);
					else
						componentPlayer.Project.FindSubsystem<SubsystemPickables>()?.AddPickable(value, 1, componentPlayer.ComponentBody.Position, null, null);
					subsystem.NourishmentAcquiredCount++;
				}
			}
			return base.OnPlayerSpawned(spawnMode, componentPlayer, position);
		}
		public override void SetClothes(ComponentClothing componentClothing, ClothingSlot slot, IEnumerable<int> clothes)
		{
			componentClothing.Entity.FindComponent<ComponentClothingMass>()?.ArmorProtection = SAGhoulsManager.CalculateSAGArmorProtection(componentClothing);
		}
		public override void InitializeCreatureTypes(SubsystemCreatureSpawn spawn, List<SubsystemCreatureSpawn.CreatureType> creatureTypes)
		{
			creatureTypes.Add(new SubsystemCreatureSpawn.CreatureType("Ghouls", SpawnLocationType.Surface, randomSpawn: true, constantSpawn: false)
			{
				SpawnSuitabilityFunction = delegate (SubsystemCreatureSpawn.CreatureType creatureType, Point3 point)
				{
					// 通用生成条件
					float shoreDistance = spawn.m_subsystemTerrain.TerrainContentsGenerator.CalculateOceanShoreDistance(point.X, point.Z);
					int humidity = spawn.m_subsystemTerrain.Terrain.GetHumidity(point.X, point.Z);
					int temperature = spawn.m_subsystemTerrain.Terrain.GetTemperature(point.X, point.Z);
					int groundBlock = Terrain.ExtractContents(spawn.m_subsystemTerrain.Terrain.GetCellValueFast(point.X, point.Y - 1, point.Z));
					int topHeight = spawn.m_subsystemTerrain.Terrain.GetTopHeight(point.X, point.Z);

					// 检查天数条件
					double day = SAGhoulsManager.GetDaysCount(spawn.Project);
					if (day < SAGhoulsManager.BloodMoonPeriodLength)
						return 0f;

					// 综合条件判断
					return shoreDistance > 30f &&
						   point.Y > 60 &&
						  (groundBlock == 8 || groundBlock == 2 || groundBlock == 261 || groundBlock == 61 || groundBlock == 7 || groundBlock == 62 || groundBlock == 4)
						   ? 1f : 0f;
				},
				SpawnFunction = delegate (SubsystemCreatureSpawn.CreatureType creatureType, Point3 point)
				{
					int totalCount = 0;
					double day = SAGhoulsManager.GetDaysCount(spawn.Project);
					if (day >= 13 && day <= 37)
					{// 前期刷怪 (13-37天，60%几率)
						string[] types = ["SAGhoul_Weak_01", "SAGhoul_Weak_02", "SAGhoul_Weak_03", "SAGhoul_Fast_01", "SAGhoul_Fast_02", "SAGhoul_Fast_03"];
						int[] counts = [2, 1, 1, 2, 1, 1];
						for (int i = 0; i < types.Length; i++)
						{
							if (spawn.m_random.Float(0f, 1f) < 0.6f)
								totalCount += spawn.SpawnCreatures(creatureType, types[i], point, counts[i]).Count;
						}
					}
					if (day >= 38 && day <= 72)
					{// 中期刷怪 (38-72天，50%几率)
						string[] types = ["SAGhoul_Fast_04", "SAGhoul_Fast_05", "SAGhoul_Weak_04", "SAGhoul_Weak_05", "SAGhoul_Strong_01", "SAGhoul_Strong_02", "SAGhoul_Strong_03"];
						int[] counts = [2, 2, 2, 2, 2, 2, 2];
						for (int i = 0; i < types.Length; i++)
						{
							if (spawn.m_random.Float(0f, 1f) < 0.6f)
								totalCount += spawn.SpawnCreatures(creatureType, types[i], point, counts[i]).Count;
						}
					}
					if (day >= 73)
					{// 后期刷怪 (73+天，50%几率)
						string[] types = [
							"SAGhoul_Fast_06", "SAGhoul_Fast_07", "SAGhoul_Weak_06", "SAGhoul_Weak_07",
							"SAGhoul_Strong_01", "SAGhoul_Strong_02", "SAGhoul_Strong_03", "SAGhoul_Strong_04",
							"SAGhoul_Strong_05", "SAGhoul_Strong_06", "SAGhoul_Strong_07", "SAGhoul_Strong_08"
						];
						int[] counts = [2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2];
						for (int i = 0; i < types.Length; i++)
						{
							if (spawn.m_random.Float(0f, 1f) < 0.6f)
								totalCount += spawn.SpawnCreatures(creatureType, types[i], point, counts[i]).Count;
						}
					}
					// 动物
					(string Type, int MinDay, float Chance, int Count)[] eliteConfigs = [
						("SAGhoul_Bear", 73, 0.02f, 1),
						("SAGhoul_Monster", 61, 0.02f, 1),
						("SAGhoul_Fatt", 85, 0.02f, 1),
						("SAGhoul_Boar", 49, 0.02f, 1),
						("SAGhoul_Bird", 13, 0.33f, 3)
					];
					for (int i = 0; i < eliteConfigs.Length; i++)
					{
						var (Type, MinDay, Chance, Count) = eliteConfigs[i];
						if (day >= MinDay && spawn.m_random.Float(0f, 1f) < Chance)
						{
							totalCount += spawn.SpawnCreatures(creatureType, Type, point, Count).Count;
						}
					}
					if (day > 48 && spawn.m_random.Float(0f, 1f) < 0.2f)// 第四波后刷鳐鱼
						totalCount += spawn.SpawnCreatures(creatureType, "SAGhoul_Ray", point, spawn.m_random.Int(1, 2)).Count;

					if (totalCount == 0)// 确保至少生成一个生物
						totalCount += spawn.SpawnCreatures(creatureType, "SAGhoul_Bird", point, 1).Count;
					return totalCount;
				}
			});
		}
	}
}

